package builder

import (
	"errors"
	"fmt"
	"slices"
	"yunj/config"
	"yunj/pkg/yunj/core/builder/buildervalidator"
	"yunj/pkg/yunj/core/builder/yimport"
	errcodeEnum "yunj/pkg/yunj/core/enum/errcode"
	"yunj/pkg/yunj/core/response"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
	"github.com/worklz/go-validate"
)

// 校验参数
type validateArgs struct {
	rules  map[string]any    // 规则
	titles map[string]string // 标题
}

type Import struct {
	Builder
	// 工作表
	sheet []string
	// 表头
	cols         []yimport.Col // 无工作表表头
	colsIdx      map[string]int
	sheetCols    map[string][]yimport.Col // 工作表表头
	sheetColsIdx map[string]map[string]int
	// 模板下载
	example string
	// 每次导入条数
	limit uint
	// 提示信息
	tips []string
	// 单行数据的处理方法
	rowFunc func(i *Import, row *yimport.Row) (err error)
	// 多行数据的处理方法
	rowsFunc func(i *Import, rows []*yimport.Row) (err error)
	// 校验参数
	validateArgs      *validateArgs
	sheetValidateArgs map[string]*validateArgs
}

// 编译时判断是否实现BuilderInterface接口
var _ BuilderInterface = (*Import)(nil)

// NewImport 创建一个新的导入构建器实例
func NewImport(ctx *gin.Context, id string) *Import {
	i := &Import{}
	SetBuilderInstance(&i.Builder, i)
	i.Type = "yunj_import"
	i.Id = id
	i.GinContext = ctx
	i.ActionHandleSort = []string{"Sheet", "Cols", "Validator", "Example", "Limit", "Tips", "Row", "Rows"}
	i.ScriptFileList = []string{util.YunjStaticUrl("/static/yunj/js/import.min.js?v=" + config.VERSION)}
	builderValidator := &buildervalidator.Import{}
	builderValidator.InitValidator(builderValidator)
	i.BuilderValidator = builderValidator
	// 配置默认值
	i.limit = 20
	i.tips = []string{
		"限制文件上传格式：xlsx/xls/csv",
		"上传数据不能包含图片、视频等媒体资源",
		"限制使用合并单元格存放数据",
	}
	return i
}

// 配置工作表
// param: func(i *Import) ([]string, error)
// param: []string
// param: string
func (i *Import) Sheet(param ...any) *Import {
	if param == nil {
		return i
	}
	if err := i.GetError(); err != nil {
		return i
	}
	for _, v := range param {
		if fun, ok := v.(func(i *Import) ([]string, error)); ok {
			i.addActionHandleFuns("Sheet", fun)
			continue
		}
		if items, ok := v.([]string); ok {
			i.addActionHandleFuns("Sheet", func(i *Import) ([]string, error) {
				return items, nil
			})
			continue
		}
		if item, ok := v.(string); ok {
			i.addActionHandleFuns("Sheet", func(i *Import) ([]string, error) {
				return []string{item}, nil
			})
			continue
		}
		i.setError("Sheet 方法传入参数错误")
	}
	return i
}

// 处理工作表的回调方法
func (i *Import) HandleSheetFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	function, ok := fun.(func(i *Import) ([]string, error))
	if !ok {
		i.setError(errors.New("Sheet 方法传入参数格式错误"))
		return i
	}
	res, err := function(i)
	if err != nil {
		i.setError(err)
		return i
	}
	if len(res) > 0 {
		i.sheet = util.SliceUnique(append(i.sheet, res...))
	}
	return i
}

// 配置表头
// param: func(i *Import, sheet string) ([]yimport.Col, error)
// param: []yimport.Col
// param: yimport.Col
func (i *Import) Cols(param ...any) *Import {
	if param == nil {
		return i
	}
	if err := i.GetError(); err != nil {
		return i
	}
	for _, v := range param {
		if fun, ok := v.(func(i *Import, sheet string) ([]yimport.Col, error)); ok {
			i.addActionHandleFuns("Cols", fun)
			continue
		}
		if items, ok := v.([]yimport.Col); ok {
			i.addActionHandleFuns("Cols", func(i *Import, sheet string) ([]yimport.Col, error) {
				return items, nil
			})
		}
		if item, ok := v.(yimport.Col); ok {
			i.addActionHandleFuns("Cols", func(i *Import, sheet string) ([]yimport.Col, error) {
				return []yimport.Col{item}, nil
			})
		}
	}
	return i
}

// 处理表头的回调方法
func (i *Import) HandleColsFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	handle, ok := fun.(func(i *Import, sheet string) ([]yimport.Col, error))
	if !ok {
		i.setError(errors.New("Cols 方法传入参数格式错误"))
		return i
	}
	if len(i.sheet) > 0 {
		if i.sheetCols == nil {
			i.sheetCols = map[string][]yimport.Col{}
		}
		if i.sheetColsIdx == nil {
			i.sheetColsIdx = map[string]map[string]int{}
		}
		for _, sheet := range i.sheet {
			res, err := handle(i, sheet)
			if err != nil {
				i.setError(err)
				return i
			}
			err = i.handleColItems(res, sheet)
			if err != nil {
				i.setError(err)
				return i
			}
		}
	} else {
		res, err := handle(i, "")
		if err != nil {
			i.setError(err)
			return i
		}
		err = i.handleColItems(res, "")
		if err != nil {
			i.setError(err)
			return i
		}
	}
	return i
}

// 处理表头项
func (i *Import) handleColItems(cols []yimport.Col, sheet string) (err error) {
	var importCols []yimport.Col
	var importColsIdx map[string]int
	if sheet == "" {
		importCols = i.cols
		importColsIdx = i.colsIdx
	} else {
		if i.sheetCols == nil {
			i.sheetCols = map[string][]yimport.Col{}
		}
		if i.sheetColsIdx == nil {
			i.sheetColsIdx = map[string]map[string]int{}
		}
		var ok bool
		importCols, ok = i.sheetCols[sheet]
		if !ok {
			importCols = []yimport.Col{}
		}
		importColsIdx, ok = i.sheetColsIdx[sheet]
		if !ok {
			importColsIdx = map[string]int{}
		}
	}
	if importCols == nil || len(importCols) <= 0 {
		importCols = []yimport.Col{}
	}
	if importColsIdx == nil {
		importColsIdx = map[string]int{}
	}
	for _, col := range cols {
		// 判断原来是否存在
		idx, exists := importColsIdx[col.Field]
		if exists {
			importCols[idx] = col
		} else {
			importCols = append(importCols, col)
			importColsIdx[col.Field] = len(importCols) - 1
		}
	}
	if sheet == "" {
		i.cols = importCols
		i.colsIdx = importColsIdx
	} else {
		if i.sheetCols == nil {
			i.sheetCols = map[string][]yimport.Col{}
		}
		if i.sheetColsIdx == nil {
			i.sheetColsIdx = map[string]map[string]int{}
		}
		i.sheetCols[sheet] = importCols
		i.sheetColsIdx[sheet] = importColsIdx
	}
	return
}

// 配置验证器
func (i *Import) Validator(param any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	if fun, ok := param.(func(i *Import) (validate.ValidatorInterface, error)); ok {
		i.addActionHandleFuns("Validator", fun)
		return i
	}
	if validator, ok := param.(validate.ValidatorInterface); ok {
		i.addActionHandleFuns("Validator", func(i *Import) (validate.ValidatorInterface, error) {
			return validator, nil
		})
	}
	return i
}

// 处理表格验证器的回调方法
func (i *Import) HandleValidatorFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	validatorFun, ok := fun.(func(i *Import) (validate.ValidatorInterface, error))
	if !ok {
		i.setError(errors.New("Validator 方法传入参数格式错误"))
		return i
	}
	validator, err := validatorFun(i)
	if err != nil {
		i.setError(err)
		return i
	}
	i.ValidatorInstance = validator
	return i
}

// 配置模板下载
// param: func(i *Import) (string, error)
// param: string
func (i *Import) Example(param ...any) *Import {
	if param == nil {
		return i
	}
	if err := i.GetError(); err != nil {
		return i
	}
	for _, v := range param {
		if fun, ok := v.(func(i *Import) (string, error)); ok {
			i.addActionHandleFuns("Example", fun)
			continue
		}
		if item, ok := v.(string); ok {
			i.addActionHandleFuns("Example", func(i *Import) (string, error) {
				return item, nil
			})
			continue
		}
		i.setError("Example 方法传入参数错误")
	}
	return i
}

// 处理模板下载的回调方法
func (i *Import) HandleExampleFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	handle, ok := fun.(func(i *Import) (string, error))
	if !ok {
		i.setError(errors.New("Example 方法传入参数格式错误"))
		return i
	}
	res, err := handle(i)
	if err != nil {
		i.setError(err)
		return i
	}
	i.example = res
	return i
}

// 配置每次导入条数
// param: func(i *Import) (string, error)
// param: string
func (i *Import) Limit(param ...any) *Import {
	if param == nil {
		return i
	}
	if err := i.GetError(); err != nil {
		return i
	}
	for _, v := range param {
		if fun, ok := v.(func(i *Import) (uint, error)); ok {
			i.addActionHandleFuns("Limit", fun)
			continue
		}
		if item, ok := v.(uint); ok {
			i.addActionHandleFuns("Limit", func(i *Import) (uint, error) {
				return item, nil
			})
			continue
		}
		i.setError("Limit 方法传入参数错误")
	}
	return i
}

// 处理每次导入条数的回调方法
func (i *Import) HandleLimitFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	handle, ok := fun.(func(i *Import) (uint, error))
	if !ok {
		i.setError(errors.New("Limit 方法传入参数格式错误"))
		return i
	}
	res, err := handle(i)
	if err != nil {
		i.setError(err)
		return i
	}
	i.limit = res
	return i
}

// 配置提示信息
// param: func(i *Import) ([]string, error)
// param: []string
// param: string
func (i *Import) Tips(param ...any) *Import {
	if param == nil {
		return i
	}
	if err := i.GetError(); err != nil {
		return i
	}
	for _, v := range param {
		if fun, ok := v.(func(i *Import) ([]string, error)); ok {
			i.addActionHandleFuns("Tips", fun)
			continue
		}
		if items, ok := v.([]string); ok {
			i.addActionHandleFuns("Tips", func(i *Import) ([]string, error) {
				return items, nil
			})
			continue
		}
		if item, ok := v.(string); ok {
			i.addActionHandleFuns("Tips", func(i *Import) ([]string, error) {
				return []string{item}, nil
			})
			continue
		}
		i.setError("Tips 方法传入参数错误")
	}
	return i
}

// 处理提示信息的回调方法
func (i *Import) HandleTipsFunc(fun any) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	handle, ok := fun.(func(i *Import) ([]string, error))
	if !ok {
		i.setError(errors.New("Tips 方法传入参数格式错误"))
		return i
	}
	res, err := handle(i)
	if err != nil {
		i.setError(err)
		return i
	}
	if len(res) > 0 {
		i.tips = util.SliceUnique(append(i.tips, res...))
	}
	return i
}

// 配置单行数据的处理方法
func (i *Import) Row(fun func(i *Import, row *yimport.Row) (err error)) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	i.rowFunc = fun
	return i
}

// 配置多行数据的处理方法
func (i *Import) Rows(fun func(i *Import, rows []*yimport.Row) (err error)) *Import {
	if err := i.GetError(); err != nil {
		return i
	}
	i.rowsFunc = fun
	return i
}

// 视图模板配置数据
func (i *Import) viewArgs() (args map[string]any) {
	args = i.Builder.viewArgs()
	if len(i.sheet) > 0 {
		args["sheet"] = i.sheet
	}
	if i.sheetCols != nil {
		args["cols"] = i.sheetCols
	} else if len(i.cols) > 0 {
		args["cols"] = i.cols
	}
	if i.example != "" {
		args["example"] = i.example
	}
	args["limit"] = i.limit
	args["tips"] = i.tips
	if err := i.GetError(); err != nil {
		ctx := i.GetGinContext()
		util.RedirectAdminTips(ctx, errcodeEnum.ERROR, err.Error())
	}

	return
}

// 处理异步数据导入
func (i *Import) HandleAsyncImport(params map[string]any) *response.JsonData {
	if err := i.GetError(); err != nil {
		return response.FailJsonData(err.Error())
	}
	i.handleActionFuns("Sheet", "Cols", "Limit", "Row", "Rows")
	if err := i.GetError(); err != nil {
		return response.FailJsonData(err.Error())
	}
	if i.rowFunc == nil && i.rowsFunc == nil {
		return response.FailJsonData("异步数据导入方法Row或Rows未设置")
	}
	itemCountRaw, exists := params["count"]
	if !exists {
		return response.FailJsonData("参数Count设置异常")
	}
	itemCount, ok := itemCountRaw.(uint)
	if !ok {
		return response.FailJsonData("参数Count错误")
	}
	if itemCount > i.limit {
		return response.FailJsonData(fmt.Sprintf("请求数量超过限制%d", i.limit))
	}
	itemsRaw, exists := params["items"]
	if !exists {
		return response.FailJsonData("参数items不能为空")
	}
	items, ok := itemsRaw.([]map[string]any)
	if !ok {
		return response.FailJsonData("参数items格式错误")
	}
	rows := make([]*yimport.Row, 0, len(items))
	for _, item := range items {
		row := yimport.NewRow(item)
		// 校验数据
		i.checkRow(row)
		rows = append(rows, row)
	}
	// 进行导入处理
	if i.rowsFunc != nil {
		_rows := make([]*yimport.Row, 0, len(rows))
		for _, row := range rows {
			if row.Status.Code == yimport.RowStatusCodeImporting {
				_rows = append(_rows, row)
			}
		}
		if err := i.rowsFunc(i, _rows); err != nil {
			return response.FailJsonData(err.Error())
		}
	} else if i.rowFunc != nil {
		for _, row := range rows {
			if row.Status.Code == yimport.RowStatusCodeImporting {
				if err := i.rowFunc(i, row); err != nil {
					return response.FailJsonData(err.Error())
				}
			}
		}
	}

	resItems := make([]map[string]any, 0, len(rows))
	for _, row := range rows {
		if row.Status.Code == yimport.RowStatusCodeImporting {
			// 未修改状态的数据默认为成功
			row.Success()
		}
		resItems = append(resItems, row.GetResponseData())
	}

	return response.SuccessJsonData(map[string]any{
		"limit": i.limit,
		"count": itemCount,
		"items": resItems,
	})
}

// 校验单行数据
func (i *Import) checkRow(row *yimport.Row) {
	// 判断sheet
	if i.IsSetSheet() {
		if row.Sheet == "" {
			row.Fail("工作表数据不存在")
			return
		}
		if !slices.Contains(i.sheet, row.Sheet) {
			row.Fail("工作表" + row.Sheet + "在导入模板中不存在")
			return
		}
	}
	// 判断cols
	var cols []yimport.Col
	if i.IsSetSheet() {
		if sheetCols, exists := i.sheetCols[row.Sheet]; exists {
			cols = sheetCols
		}
		if len(cols) <= 0 {
			row.Fail("工作表" + row.Sheet + "表头cols未配置")
			return
		}
	} else {
		cols = i.cols
		if len(cols) <= 0 {
			row.Fail("表头cols未配置")
			return
		}
	}
	// 进行验证器验正
	validateArgs := i.getValidateArgs(row.Sheet, cols)
	if validateArgs == nil {
		return
	}
	validator, err := i.GetValidator()
	if err != nil {
		row.Fail(fmt.Sprintf("验证器配置异常！%v", err))
		return
	}
	err = util.DatasValidate(validator, row.Data, validateArgs.rules, validateArgs.titles, "ImportRow")
	if err != nil {
		row.Fail(err.Error())
		return
	}
}

// 获取校验参数
func (i *Import) getValidateArgs(sheet string, cols []yimport.Col) *validateArgs {
	if len(cols) <= 0 {
		return nil
	}
	if sheet != "" {
		if sheetValidateArgs, exists := i.sheetValidateArgs[sheet]; exists {
			return sheetValidateArgs
		}
	} else {
		if i.validateArgs != nil {
			return i.validateArgs
		}
	}
	args := &validateArgs{rules: map[string]any{}, titles: map[string]string{}}
	for _, col := range cols {
		if col.Verify == "" {
			continue
		}
		args.rules[col.Field] = col.Verify
		title := col.Title
		if title == "" {
			title = col.Field
		}
		args.titles[col.Field] = title
	}
	if sheet != "" {
		if i.sheetValidateArgs == nil {
			i.sheetValidateArgs = map[string]*validateArgs{}
		}
		i.sheetValidateArgs[sheet] = args
	} else {
		i.validateArgs = args
	}
	return args
}

// 判断是否设置sheet
func (i *Import) IsSetSheet() bool {
	i.handleActionFuns("Sheet")
	return len(i.sheet) > 0
}
